<?php
/**
 * A class that contains methods for working with filesystem
 * @author Kirill A Egorov 2011 <ksam1000@gmail.com>
 * @license GPLv3
 */
class File
{
	const Files_Dirs = 0;
    const Files_Only = 1;
    const Dirs_Only = 2;
     /**
      * Get file extension
      * @param string $name
      */
     static public function getExt($name)
     {
        if(!$ldPos = strrpos( $name , "." ))
            return false;
           
	     return substr($name , $ldPos);
      }
      /**
       * Add path separator to the end of string 
       * @param string $path
       * @return string
       */
      static public function fillEndSep($path){
           if($path[strlen($path)-1] !== DIRECTORY_SEPARATOR)
              $path.= DIRECTORY_SEPARATOR;
              
            return $path;
      }
   /**
    * Get file list
    * @param string $path
	* @param array $filter - optional  aray of file extensions to search for
	* @param boolean $recursive - optional	use recursion (default true)
	* @param string $type - optional File::Dirs_Only | File::Files_Dirs | File::Files_Only (default File::Files_Dirs)
	* @param string $mode - optional RecursiveIteratorIterator::SELF_FIRST | RecursiveIteratorIterator::CHILD_FIRST (default RecursiveIteratorIterator::SELF_FIRST)
	*/
     static public function scanFiles ($path,  $filter = array(), $recursive = true, $type = File::Files_Dirs, $mode = RecursiveIteratorIterator::SELF_FIRST){	
      	$path = self::fillEndSep($path);
		$files = array();      	
      	$collectDirs = false;
      	$collectFiles = false;
  		
		switch($type) {
           	case self::Files_Only :
           		$mode = RecursiveIteratorIterator::LEAVES_ONLY;
      			$collectFiles = true;
				break;
			case self::Dirs_Only :
				$collectDirs = true;
				break;
			case self::Files_Dirs :
				$collectDirs = true;
      			$collectFiles = true;
				break;
		}
		try {
	       	if ($recursive)
				$dirIterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($path, RecursiveDirectoryIterator::SKIP_DOTS), $mode);
	       	else 
	       		$dirIterator = new FilesystemIterator($path, FilesystemIterator::SKIP_DOTS);
     	} catch (Exception $e) {
     		throw new Exception('You tried to read nonexistent dir');
     	}
	       		
		foreach($dirIterator as $name => $object){
			$add = false;
			$isDir = $object->isDir();

			if(($isDir && $collectDirs) || (!$isDir && $collectFiles))
				$add = true;

			if (!empty($filter))
				if(!$isDir && !in_array(self::getExt($name), $filter , true))
					$add = false;
				
			if ($add)
				$files[] = $name;
		}
		return $files;
	}
	/**
	 * Archives some files
	 * @param string $archivName
	 * @param string $dest - must be with the lastest slash
	 * @param array $files
	 * @param string $pseudoRoot
	 * @return bool
	 */
	static public function zipFiles($archivName, $dest, $files, $pseudoRoot) {
		$zip = new ZipArchive;
		
		/**
		 * ZIPARCHIVE::CREATE (integer)
		 * 		Create the archive if it does not exist.
		 */
		if ($zip->open($dest . $archivName . '.zip', ZIPARCHIVE::CREATE) !== true)
			return false;

		if (!empty($files))
			if (is_array($files))
				foreach ($files as $file) {
					$zip->addFile($file, str_replace($pseudoRoot, '', $file));
				}
			else
				$zip->addFile($files, str_replace($pseudoRoot, '', $files));
		
	   	$zip->close();
	   	return true;
	}
	/**
	 * Extract all files 
	 * @param string $source
	 * @param string $destination
	 * @param array | string $fileEntries - optional - The entries to extract. 
	 * 										It accepts either a single entry name or an array of names.
	 * @return bool
	 */
	static public function unzipFiles($source, $destination, $fileEntries = false) {
		$zip = new ZipArchive;
		
		if ($zip->open($source) !== true)
			return false;
		
		if (!empty($fileEntries))
			$zip->extractTo($destination, $fileEntries);
		else
			$zip->extractTo($destination);
		
		$zip->close();
		return true;
	}
	/**
	 * Recursively remove files and dirs from given $pathname
	 * @param string $pathname
	 * @param bool $removeParentDir
	 */
	static public function rmdirRecursive($pathname, $removeParentDir = false) {
		$filesDirs = File::scanFiles($pathname, false, true, File::Files_Dirs, RecursiveIteratorIterator::CHILD_FIRST);
		
		foreach ($filesDirs as $v)
			if (is_file($v))
				unlink($v);
			elseif (is_dir($v))
				rmdir($v);
		
		if ($removeParentDir)
			rmdir($pathname);
	}
}